/* XSLEngine : applique une feuille de style XSLT à un document XLK.
 */


#include "XSLEngine.h"

#include <cstddef>
#include <list>
#include <algorithm>


XSLEngine::XSLEngine(XSLStylesheet *p_xslStylesheet, Balise *p_xmlDoc)
 : xslStylesheet(p_xslStylesheet), xmlDoc(p_xmlDoc), transformedXMLDoc(NULL)
 {
 	/* Bloc vide */
 }

/* Appliqye la transformation XSL */
bool XSLEngine::transformXMLDoc( )
{
	Noeud *orgDoc = xmlDoc;
	Noeud *transDoc;

	errMsg.clear();

	std::list<Noeud*> rootTemp;
	if (!xslStylesheet->getCopiePTemplateContent(std::string("/"), rootTemp))
	{
		errMsg = "Pas de template pour la racine '/' : rien à faire.";
		return false;
	}
	if (rootTemp.size() != 1)
	{
		errMsg = "Le template de la racine doit avoir UNE SEULE racine.";
		return false;
	}

	transDoc = rootTemp.front();
	if (transDoc->getType() == TEXTE_e)
	{
		errMsg = "Le doc transformé doit avoir une balise";
		return false;
	}
	transformedXMLDoc = (Balise*)transDoc;
	recurTransform(orgDoc, transDoc);

	return true;
}

/*
 * Pour le moment, pour que sa marche, transDoc ne doit pas etre apply-template*/
void XSLEngine::recurTransform(Noeud *orgDoc, Noeud *transDoc)
{
	Balise* bTransDoc;
	std::list<Noeud*> transChilds;
	std::list<Noeud*>::iterator applyTemplateIt;
	const Noeud* const applyTemplateElm = xslStylesheet->getApplyTemplates();
	Noeud *prec;

	bool endBranch = false;
	while (!endBranch)
	{
		if (transDoc->getType() == BALISE_e)
		{
			bTransDoc = (Balise*)transDoc;
			transChilds = bTransDoc->getFils();
			applyTemplateIt = std::find(transChilds.begin(), transChilds.end(), applyTemplateElm);
			prec = *applyTemplateIt;
			if ((transChilds.size() == 1)
				&& (applyTemplateIt == transChilds.end()))
			{
				transDoc = transChilds.front();
				transChilds.clear();
			}
			else
			{
				endBranch = true;
			}
		}
		else
		{
			endBranch = true;
		}
	}

	if (transDoc->getType() == TEXTE_e)
	{ /* On est tombé sur du texte : plus rien à faire dans cette direction */
		return;
	}

	std::list<Noeud*>::iterator transChildsIt;
	for (transChildsIt = transChilds.begin(); transChildsIt != transChilds.end(); transChildsIt++)
	{
		if (*transChildsIt == applyTemplateElm)
		{ /* Balise apply-template : on applique les templates */
			Balise *bOrgDoc = (Balise*)orgDoc;
			std::list<Noeud*> orgChilds = bOrgDoc->getFils();
			std::list<Noeud*>::iterator orgChildsIt;
			for (orgChildsIt = orgChilds.begin(); orgChildsIt != orgChilds.end(); orgChildsIt++)
			{
				if ((*orgChildsIt)->getType() == BALISE_e)
				{
					Balise* bOrgChild = (Balise*)*orgChildsIt;
					std::list<Noeud*> tempChilds;
					if (xslStylesheet->getCopiePTemplateContent(bOrgChild->getNom(), tempChilds))
					{
						std::list<Noeud*>::iterator tempChildsIt;
						for (tempChildsIt = tempChilds.begin(); tempChildsIt != tempChilds.end(); tempChildsIt++)
						{
							bTransDoc->ajouterFilsApres(*tempChildsIt, prec);
							prec = *tempChildsIt;
							recurTransform(*orgChildsIt, *tempChildsIt);
						}
					}
					else
					{
						bTransDoc->ajouterFilsApres((*orgChildsIt)->getCopieProfonde(), prec);
					}
				}
				else
				{
					bTransDoc->ajouterFilsApres((*orgChildsIt)->getCopieProfonde(), prec);
				}
			}
		}
		else
		{
			recurTransform(orgDoc, *transChildsIt);
		}
	}
	bTransDoc->detacherFils((Noeud*)applyTemplateElm);
}

/* Récupérer le document XML généré, ou NULL si il n'a pas été généré.
 * Pour générer le document XML transformé par la feuille de style XSLT,
 * utilisé transformXMLDoc().
 */
Balise* XSLEngine::getTransformedXMLDoc( )
{
	return transformedXMLDoc;
}

/* Obtenir la raison d'une erreur de la transformation d'un document XML */
const std::string& XSLEngine::getErrMsg() const
{
	return errMsg;
}
